package com.jj.net.kcp;

import com.google.protobuf.GeneratedMessageV3;
import com.jj.battle.protocol.GameProto;
import com.jj.battle.protocol.ProtocolId;
import com.jj.config.Constants;
import com.jj.core.rpc.RPCManager;
import com.jj.message.PBMessageFactory;
import com.jj.message.battle.UserMessage;
import com.jj.net.Context;
import com.jj.net.Message;
import com.jj.net.impl.AbstractChannelListenerImpl;
import com.jj.net.tcp.TcpChannelListener;
import com.jj.service.player.Player;
import com.jj.service.player.PlayerImpl;
import com.jj.service.player.PlayerManagerImpl;
import com.jj.service.room.Room;
import com.jj.service.room.RoomImpl;
import com.jj.service.room.RoomManagerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Copyrights: QidianGroup@JJ
 *
 * @author: LuHan
 * @date: 2018/1/15, 10:43
 */
@Component
public class KcpChannelListener extends AbstractChannelListenerImpl{
    private static Logger logger = LoggerFactory.getLogger(KcpChannelListener.class);

    @Autowired
    private PlayerManagerImpl playerManager;

    @Autowired
    private RoomManagerImpl roomManager;

    @Autowired
    private PBMessageFactory pbMessageFactory;

    @Autowired
    private TcpChannelListener tcpChannelListener;


    @Override
    public void onRcv(Message message, Context ctx) {
        logger.debug("onRCV {} from {}", message, ctx.getChannel().remote());
        Long uid = (Long) ctx.getAttr(Constants.USER_ID_KEY);
        if(uid == null){
            logger.error("unknown kcp conenction {}, ignore:{}",
                    ctx.getChannel().remote(), message);
            return;
        }

        if(message instanceof UserMessage){
            UserMessage userMessage = (UserMessage) message;
            GeneratedMessageV3 pbMsg =
                    pbMessageFactory.build(userMessage.getMsgID(), userMessage.getPayload());
            logger.debug("KcpChannelListener rcv {}", message);
            ProtocolId.ProtoId protoId = ProtocolId.ProtoId.forNumber(userMessage.getMsgID());
            if(protoId == null){
                tcpChannelListener.onRcv(userMessage, ctx);
                return;
            }
            //TODO:process pb message here
            switch (protoId){
                case MSG_OPERATION:
                    {
                        GameProto.PKG_OPERATION operation = (GameProto.PKG_OPERATION) pbMsg;
                        logger.debug("rcv operation:{}", operation);
                        Player player = playerManager.getPlayer(uid);
                        if(player != null){
                            Room room = player.getRoom();
                            if(room != null){
                                room.processCmd(uid, operation);
                            }else{
                                logger.warn("room not found for player {}", uid);
                            }
                        }else{
                            logger.error("player not found for {}", uid);
                        }
                    }
                    break;
                case MSG_FRAME:
                    logger.error("not implement for {}", pbMsg);
                    break;
                case MSG_SYN_STATE_REQ:
                    {
                        GameProto.PKG_SYN_STATE_REQ req = (GameProto.PKG_SYN_STATE_REQ) pbMsg;
                        int beginFrameSeq = req.getFrameNo();
                        PlayerImpl player = (PlayerImpl) playerManager.getPlayer(uid);
                        if(player != null){
                            Room room = player.getRoom();
                            if(room != null){
                                room.synState(beginFrameSeq, player);
                                player.setHasSyn(true);
                                logger.debug("set {} syn", uid);
                            }else{
                                logger.warn("room not found for player {}", uid);
                            }
                        }else{
                            logger.error("player not found for {}", uid);
                        }
                    }
                    break;
                case MSG_SYN_STATE_NTF:
                    logger.error("not implement for {}", pbMsg);
                    break;
                default:
                    logger.error("unknown msgId:{}", userMessage.getMsgID());
                    tcpChannelListener.onRcv(userMessage, ctx);
                    return;
            }
        }
    }


    @Override
    public void onClosed(Context ctx) {
        Long uid = (Long) ctx.getAttr(Constants.USER_ID_KEY);
        logger.debug("onClosed from {}, bind uid:{}", ctx, uid);
        if(uid == null){
            return;
        }else{
            Player player = playerManager.getPlayer(uid);
            if(player != null){
                Room room = player.getRoom();
                if(room != null){
                    room.leave(player);
                }else{
                    logger.debug("can not find room for player {}", player.getUserId());
                }
            }else{
                logger.debug("can not find player {}", uid);
            }
            roomManager.leave(uid);
        }
    }

    @Override
    public void onOpen(Context ctx) {
        logger.debug("onOpen from {}", ctx);
    }
}
